Add support for Ruby 1.9.x.

Akinori MUSHA 10 years ago
parent
commit
59482ee937
2 changed files with 89 additions and 1 deletions
  1. 4 1
      lib/ar_mysql_column_charset.rb
  2. 85 0
      lib/prepend.rb

+ 4 - 1
lib/ar_mysql_column_charset.rb

@@ -1,5 +1,8 @@
1 1
 require 'active_record'
2 2
 
3
+# Module#prepend support for Ruby 1.9
4
+require 'prepend' unless Module.method_defined?(:prepend)
5
+
3 6
 module ActiveRecord::ConnectionAdapters
4 7
   class ColumnDefinition
5 8
     module CharsetSupport
@@ -77,4 +80,4 @@ module ActiveRecord::ConnectionAdapters
77 80
       prepend CharsetSupport
78 81
     end
79 82
   end
80
-end if Module.method_defined?(:prepend)  # ruby >=2.0
83
+end

+ 85 - 0
lib/prepend.rb

@@ -0,0 +1,85 @@
1
+# Fake implementation of prepend(), which does not support overriding
2
+# inherited methods nor methods that are formerly overridden by
3
+# another invocation of prepend().
4
+#
5
+# Here's what <Original>.prepend(<Wrapper>) does:
6
+#
7
+# - Create an anonymous stub module (hereinafter <Stub>) and define
8
+#   <Stub>#<method> that calls #<method>_without_<Wrapper> for each
9
+#   instance method of <Wrapper>.
10
+#
11
+# - Rename <Original>#<method> to #<method>_without_<Wrapper> for each
12
+#   instance method of <Wrapper>.
13
+#
14
+# - Include <Stub> and <Wrapper> into <Original> in that order.
15
+#
16
+# This way, a call of <Original>#<method> is dispatched to
17
+# <Wrapper><method>, which may call super which is dispatched to
18
+# <Stub>#<method>, which finally calls
19
+# <Original>#<method>_without_<Wrapper> which is used to be called
20
+# <Original>#<method>.
21
+#
22
+# Usage:
23
+#
24
+#     class Mechanize
25
+#       # module with methods that overrides those of X
26
+#       module Y
27
+#       end
28
+#
29
+#       unless X.respond_to?(:prepend, true)
30
+#         require 'mechanize/prependable'
31
+#         X.extend(Prependable)
32
+#       end
33
+#
34
+#       class X
35
+#         prepend Y
36
+#       end
37
+#     end
38
+class Module
39
+  def prepend(mod)
40
+    stub = Module.new
41
+
42
+    mod_id = (mod.name || 'Module__%d' % mod.object_id).gsub(/::/, '__')
43
+
44
+    mod.instance_methods.each { |name|
45
+      method_defined?(name) or next
46
+
47
+      original = instance_method(name)
48
+      next if original.owner != self
49
+
50
+      name = name.to_s
51
+      name_without = name.sub(/(?=[?!=]?\z)/) { '_without_%s' % mod_id }
52
+
53
+      arity = original.arity
54
+      arglist = (
55
+        if arity >= 0
56
+          (1..arity).map { |i| 'x%d' % i }
57
+        else
58
+          (1..(-arity - 1)).map { |i| 'x%d' % i } << '*a'
59
+        end << '&b'
60
+      ).join(', ')
61
+
62
+      if name.end_with?('=')
63
+        stub.module_eval %{
64
+          def #{name}(#{arglist})
65
+            __send__(:#{name_without}, #{arglist})
66
+          end
67
+        }
68
+      else
69
+        stub.module_eval %{
70
+          def #{name}(#{arglist})
71
+            #{name_without}(#{arglist})
72
+          end
73
+        }
74
+      end
75
+      module_eval {
76
+        alias_method name_without, name
77
+        remove_method name
78
+      }
79
+    }
80
+
81
+    include stub
82
+    include mod
83
+  end
84
+  private :prepend
85
+end unless Module.method_defined?(:prepend)